package untils

import (
	__ "api-gateway/basic/proto"
	"fmt"
	"github.com/xuri/excelize/v2"
	"math"
	"reflect"
)

func CreateExcel(data []*__.SummarizeList, excelTableName string) {
	// 创建一个新的Excel文件
	f := excelize.NewFile()
	// 创建一个工作表
	index, _ := f.NewSheet("health")

	if err := WriteStructsToSheet(f, "health", data); err != nil {
		fmt.Println("导出失败:", err)
		return
	}

	// 设置活动工作表
	f.SetActiveSheet(index)

	// 保存文件
	if err := f.SaveAs(excelTableName + ".xlsx"); err != nil {
		fmt.Println(err)
	}
}

// writeStructsToSheet 根据结构体切片自动生成带表头与基础样式的表格
func WriteStructsToSheet[T any](f *excelize.File, sheet string, data []T) error {
	var elemType reflect.Type
	if len(data) > 0 {
		elemType = reflect.TypeOf(data[0])
	} else {
		var zero T
		elemType = reflect.TypeOf(zero)
	}
	if elemType.Kind() == reflect.Ptr {
		elemType = elemType.Elem()
	}
	if elemType.Kind() != reflect.Struct {
		return fmt.Errorf("data 必须是结构体切片")
	}

	type fieldMeta struct {
		index  int
		header string
	}
	var fields []fieldMeta
	for i := 0; i < elemType.NumField(); i++ {
		sf := elemType.Field(i)
		if sf.PkgPath != "" {
			continue
		}
		header := sf.Tag.Get("excel")
		if header == "" {
			header = sf.Name
		}
		fields = append(fields, fieldMeta{index: i, header: header})
	}
	if len(fields) == 0 {
		return fmt.Errorf("未找到可导出的字段")
	}

	// 写入表头
	for c := 0; c < len(fields); c++ {
		colName, _ := excelize.ColumnNumberToName(c + 1)
		_ = f.SetCellValue(sheet, fmt.Sprintf("%s1", colName), fields[c].header)
	}

	// 写入数据
	for r := 0; r < len(data); r++ {
		rv := reflect.ValueOf(data[r])
		if rv.Kind() == reflect.Ptr {
			rv = rv.Elem()
		}
		for c := 0; c < len(fields); c++ {
			colName, _ := excelize.ColumnNumberToName(c + 1)
			cell := fmt.Sprintf("%s%d", colName, r+2)
			_ = f.SetCellValue(sheet, cell, rv.Field(fields[c].index).Interface())
		}
	}

	// 范围与样式
	lastColName, _ := excelize.ColumnNumberToName(len(fields))
	lastRow := len(data) + 1

	headerStyle, _ := f.NewStyle(&excelize.Style{
		Font:      &excelize.Font{Bold: true, Color: "#FFFFFF"},
		Fill:      excelize.Fill{Type: "pattern", Color: []string{"#4472C4"}, Pattern: 1},
		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
	})
	_ = f.SetCellStyle(sheet, "A1", fmt.Sprintf("%s1", lastColName), headerStyle)
	_ = f.SetRowHeight(sheet, 1, 22)

	if lastRow > 1 {
		bodyStyle, _ := f.NewStyle(&excelize.Style{
			Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center"},
		})
		_ = f.SetCellStyle(sheet, "A2", fmt.Sprintf("%s%d", lastColName, lastRow), bodyStyle)
	}

	// 冻结首行
	_ = f.SetPanes(sheet, &excelize.Panes{Freeze: true, YSplit: 1, TopLeftCell: "A2", ActivePane: "bottomLeft"})

	// 自适应列宽
	headers := make([]string, len(fields))
	indices := make([]int, len(fields))
	for i := range fields {
		headers[i] = fields[i].header
		indices[i] = fields[i].index
	}
	AutoFitColumns(f, sheet, headers, indices, data)

	return nil
}

// 根据表头与数据内容估算列宽
func AutoFitColumns[T any](f *excelize.File, sheet string, headers []string, indices []int, data []T) {
	for c := 0; c < len(headers); c++ {
		maxChars := DisplayWidth(headers[c])
		for r := 0; r < len(data); r++ {
			rv := reflect.ValueOf(data[r])
			if rv.Kind() == reflect.Ptr {
				rv = rv.Elem()
			}
			s := fmt.Sprint(rv.Field(indices[c]).Interface())
			if w := DisplayWidth(s); w > maxChars {
				maxChars = w
			}
		}
		width := math.Min(60, float64(maxChars)*1.2+2)
		colName, _ := excelize.ColumnNumberToName(c + 1)
		_ = f.SetColWidth(sheet, colName, colName, width)
	}
}

func DisplayWidth(s string) int {
	count := 0
	for _, r := range s {
		if r <= 0x7F {
			count += 1
		} else {
			count += 2
		}
	}
	if count == 0 {
		return 1
	}
	return count
}
